import sys
import pygame
from bullet import Bullet
from alien import Alien
from time import sleep
from music import Music
# 将在主程序中使用的函数提取出来，对代码进行重构

def check_event(ai_settings, screen, ship: '飞船的对象', bullets, stats, play_button, aliens, sb):
    """对于鼠标和键盘的事件处理检查处理函数"""
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            # 在当前事件是pygame的退出事件
            sys.exit()
        elif event.type == pygame.KEYDOWN:
            check_keydown(event, ship, ai_settings, screen, bullets, stats)
        elif event.type == pygame.KEYUP:
            check_keyup(event, ship)
        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_x, mouse_y = pygame.mouse.get_pos()
            check_play_button(stats, play_button, mouse_x, mouse_y, ai_settings, screen, aliens, ship, bullets, sb)


def check_keydown(event, ship, ai_settings, screen, bullets, stats):
    """键盘按下的事件处理"""
    if event.key == pygame.K_RIGHT:
        # 检测当前是鼠标按下且按下的按键是右方向键
        ship.moveRight = True
    elif event.key == pygame.K_LEFT:
        # 检测当前是鼠标按下且按下的按键是左方向键
        ship.moveLeft = True
    elif event.key == pygame.K_SPACE:
        # 当前按下的按键是空格键的时候创建一个新的子弹对象并存储到传递的子弹编组中,并设置子弹的发射声音
        stats.bullet_music.playBulletMusic()
        fire_bullets(bullets, ai_settings, screen, ship)
        # stats.bullet_music.stopBackMusic()

    elif event.key == pygame.K_q:
            # 当前按下的是'q'键的时候借宿游戏
            sys.exit()

def check_keyup(event, ship):
    """键盘松开的事件处理"""
    if event.key == pygame.K_RIGHT:
        # 检测当前是鼠标按下且按下的按键是右方向键
        ship.moveRight = False
    elif event.key == pygame.K_LEFT:
        # 检测当前是鼠标按下且按下的按键是左方向键
        ship.moveLeft = False

def update_screen(ai_setting: '游戏的设置', screen: '当前显示的屏幕对象', ship: '需要显示的飞船的对象', bullets: '子弹编组数据',
                  aliens: '外星人对象数据编组', stats: '游戏状态存储信息', play_button:'屏幕显示按钮', sb:'记分牌的对象'):
    """刷新页面的函数"""
    # 处理当前显示页面的颜色
    screen.fill(ai_setting.screen_bg_color)
    # 重新绘制子弹在屏幕上的显示
    for bullet in bullets.sprites():
        bullet.draw_bullet()
    # 显示当前的飞船图像
    ship.blitme()
    # 显示外星人的图像
    aliens.draw(screen)
    # 显示记分牌图像
    sb.show_score()
    # 在非激活状态的情况下显示按钮
    if not stats.game_active:
        play_button.draw_button()
    # 刷新页面
    pygame.display.flip()

def bullets_update(ai_settings, screen, ship, aliens, bullets, sb, stats):
    """更新子弹位置，剔除已经在屏幕外面的子弹数据"""
    bullets.update()
    # 删除已经不在屏幕上显示的子弹，使用bullets的副本进行循环删除
    for bullet in bullets.copy():
        if bullet.rect.bottom <= 0:
            bullets.remove(bullet)
    check_bullets_aliens_collisiions(ai_settings, screen, ship, aliens, bullets, sb, stats)

def check_bullets_aliens_collisiions(ai_settings, screen, ship, aliens, bullets, sb, stats):
    """检测外星人和子弹的碰撞"""
    # 检测子弹和移动的外星人之间的碰撞，如果子弹和外星人碰撞了那么删除子弹和对应的外星人
    collisions = pygame.sprite.groupcollide(bullets, aliens, False, True)
    if collisions:
        for aliens in collisions.values():
            stats.score += ai_settings.alien_point*len(aliens)
        sb.prep_score()
    check_high_score(stats, sb)
    # 检测外星人的group的数量，在素有外星人都v被消灭的时候，清楚子弹新创建一群外星人出来
    if len(aliens) == 0:
        # 所有的外星人都被消灭之后将游戏速度递增
        ai_settings.increase_speed()
        bullets.empty()
        # 在所有的外星人都被消灭一次的时候登记提升一个等级
        stats.level += 1
        sb.prep_level()
        create_fleet(ai_settings, screen, aliens, ship)

def check_fleet_edges(ai_settions, aliens):
    """检测外星人群中是否有外星人碰到了屏幕的边缘，有的情况下改变外星人群的移动方向并向下移"""
    for alien in aliens.sprites():
        if alien.check_edges():
            change_fleet_direction(ai_settions, aliens)
            break

def change_fleet_direction(ai_settings, aliens):
    """将整个外星人块向下移动并修改外星人在水平方向上的移动方向"""
    for alien in aliens.sprites():
        alien.rect.y += ai_settings.fleet_drop_speed
    ai_settings.fleet_direction *= -1

def alien_update(ai_settings, ship, aliens, stats, screen, bullets, sb):
    """更新外星人阵列中所有外星人的位置"""
    check_fleet_edges(ai_settings, aliens)
    aliens.update()
    # 检测外星人和飞船之间的碰撞
    if pygame.sprite.spritecollideany(ship, aliens):
        ship_hit(ai_settings, stats, screen, ship, aliens, bullets, sb)
    # 检查是否外星人到达了屏幕的底部
    check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets, sb)

def ship_hit(ai_settings, stats, screen, ship, aliens, bullets, sb):
    """外星人碰撞之后要做的事情是（1）ship的limit数量减少1；（2）外星人和子弹都设置为空；
    （3）创建新的外星人设置飞船到屏幕中间；（4）停顿0.5秒"""
    if stats.ship_left > 0:
        # 统计信息中飞船剩余的数量减去1
        stats.ship_left -= 1
        # 更新飞船数量在屏幕上的显示信息
        sb.prep_ship()
        # 将子弹和外星人都设置为空
        aliens.empty()
        bullets.empty()

        # 重新创建外星人并设置飞船到屏幕地址中心位置
        create_fleet(ai_settings, screen, aliens, ship)
        ship.center_ship()

        # 暂停0.5秒
        sleep(0.5)
    else:
        stats.game_active = False
        # 设置鼠标的光标可见
        pygame.mouse.set_visible(True)
        # 所有的飞船都已经完蛋了停止播放背景音乐
        stats.background_music.stopBackMusic()

def check_aliens_bottom(ai_settings, stats, screen, ship, aliens, bullets, sb):
    """检测是否有外星人到达了屏幕的底端"""
    # 首先获取屏幕底端的数值
    screen_rect = screen.get_rect()
    for alien in aliens.sprites():
        if alien.rect.bottom >= screen_rect.bottom:
            """外星人碰到了屏幕的底端就和碰到飞船一样处理"""
            ship_hit(ai_settings, stats, screen, ship, aliens, bullets, sb)


def fire_bullets(bullets, ai_settings, screen, ship):
    """子弹的发射函数"""
    # 现在屏幕上允许的子弹的数量最大不能超过配置类中设置的数量
    if len(bullets) < ai_settings.bullets_allowed:
        bullet = Bullet(ai_settings, screen, ship)
        bullets.add(bullet)

def get_number_alienx(ai_settings, alienwidth):
    """计算每一行能够显示的外星人图像的数量"""
    # 计算屏幕中一行可供显示外星人图像的屏幕宽度
    avaiable_space_x = ai_settings.screen_width - 2 * alienwidth
    # 计算每一行能够显示的外星人的数量
    number_alien_x = int(avaiable_space_x / (2 * alienwidth))
    return number_alien_x

def create_alien(ai_settings, screen, aliens, number, row_number):
    """创建外星人并存储到编组中"""
    alien = Alien(ai_settings, screen)
    alienwidth = alien.rect.width
    alien.x = (2 * number + 1) * alienwidth
    alien.rect.x = alien.x
    alien.rect.y = (2*row_number + 1) * alien.rect.height
    # 将创建好的外星人对象
    aliens.add(alien)

def get_alien_rows(ai_settings, ship_height, alien_height):
    """获取能够显示的外星人的列数"""
    # 计算可供显示外星人的纵向位置的高度
    available_space_y = ai_settings.screen_height - 3*alien_height - ship_height
    number_alien_y = int(available_space_y/(2*alien_height))
    return number_alien_y


def create_fleet(ai_settings, screen, aliens, ship):
    """创建外星人群"""
    # 创建一个外星人计算出每一行可以容纳的外星人的数量，每个外星人之间的间隔是一个外星人的宽度
    alien = Alien(ai_settings, screen)
    # 获取每一行上能够显示的外星人的图像数量信息
    number_alien_x = get_number_alienx(ai_settings, alien.rect.width)
    # 获取能够显示的外星人的函数
    rownumber = get_alien_rows(ai_settings, ship.rect.height, alien.rect.height)
    # 创建一行外星人的数据
    for row_number in range(rownumber):
        for number in range(number_alien_x):
            create_alien(ai_settings, screen, aliens, number, row_number)

def check_play_button(stats, play_button, mouse_x, mouse_y, ai_settings, screen, aliens, ship, bullets, sb):
    """玩家单击play_button的时候"""
    button_collide = play_button.rect.collidepoint(mouse_x, mouse_y)
    # 鼠标点击了按钮的位置且当前游戏不是激活状态的时候才生效
    if button_collide and not stats.game_active:
        # 重新设置外星人的统计信息
        stats.reset_stats()
        stats.game_active = True

        # 重新设置游戏的配置处理
        ai_settings.init_dynamic_settings()

        # 游戏在激活状态下当前屏幕下设置光标不显示
        pygame.mouse.set_visible(False)

        # 重置记分牌的图像
        sb.prep_level()
        sb.prep_high_score()
        sb.prep_score()
        sb.prep_ship()

        # 清空外星人和子弹的数据
        aliens.empty()
        bullets.empty()

        # 重新创建一群外星人并将飞船居中显示
        create_fleet(ai_settings, screen, aliens, ship)
        ship.center_ship()
        stats.background_music.playBackMusic()

def check_high_score(stats, sb):
    """检查是否出现了最高得分"""
    if stats.score > stats.high_score:
        stats.high_score = stats.score
    sb.prep_high_score()





